package com.mapproject.industrymap.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.*;

public class JwtUtil {
    private static final Logger logger = LoggerFactory.getLogger(JwtUtil.class);
    public static final long EXPIRATION_TIME = 12*60* 60 * 1000L; // 12 hour
    public static final String SECRET = "wjghkclogin";//please change to your own encryption secret.
    public static final String TOKEN_PREFIX = "Bearer ";
    public static final String HEADER_STRING = "Authorization";
    public static final String USER_NAME = "username";

    public static String generateToken(String loginname,int userid) {
        HashMap<String, Object> map = new HashMap<>();
        //you can put any data in the map
        map.put(USER_NAME, loginname);
        map.put("userid",userid);
        String jwt = Jwts.builder()
                .setIssuer("wjghkcsjy")
                .setClaims(map)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
        return jwt; //jwt前面一般都会加Bearer
    }

    public static HttpServletRequest validateTokenAndAddUserIdToHeader(HttpServletRequest request) {
        String token = request.getHeader(HEADER_STRING);
        if (token != null) {
            // parse the token.
            try {
                Map<String, Object> body = Jwts.parser()
                        .setSigningKey(SECRET)
                        .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
                        .getBody();
                return new CustomHttpServletRequest(request, body);
            } catch (Exception e) {
                logger.info(e.getMessage());
                throw new TokenValidationException(e.getMessage());
            }
        } else {
            throw new TokenValidationException("Missing token");
        }
    }

    public static class CustomHttpServletRequest extends HttpServletRequestWrapper {
        private Map<String, String> claims;

        public CustomHttpServletRequest(HttpServletRequest request, Map<String, ?> claims) {
            super(request);
            this.claims = new HashMap<>();
            claims.forEach((k, v) -> this.claims.put(k, String.valueOf(v)));
        }

        @Override
        public Enumeration<String> getHeaders(String name) {
            if (claims != null && claims.containsKey(name)) {
                return Collections.enumeration(Arrays.asList(claims.get(name)));
            }
            return super.getHeaders(name);
        }

        public Map<String, String> getClaims() {
            return claims;
        }
    }

    static class TokenValidationException extends RuntimeException {
        private static final long serialVersionUID = -5090455416508590445L;

        public TokenValidationException(String msg) {
            super(msg);
        }
    }
    /**
     * 获取 Claims 实例
     * Claims ：一个 JWT声明集 。
     *   这最终是一个 JSON 映射，可以向其中添加任何值，但为了方便起见，JWT 标准名称作为类型安全的 getter 和 setter 提供。
     *   因为这个接口扩展了Map&lt;String, Object&gt; , 如果您想添加自己的属性，只需使用 map 方法，
     *   例如：
     *      claims.put("someKey", "someValue");
     *
     * @param jwt
     * @return
     */
    public static Claims getBody(String jwt) {
        return Jwts.parser()
                .setSigningKey(SECRET)
                .parseClaimsJws(jwt.replace(TOKEN_PREFIX, ""))
                .getBody();
    }


    /**
     * 判断 JWT 是否已过期
     *
     * @param jwt
     * @return
     */
    public static boolean isExpiration(String jwt) {
        return getBody(jwt)
                //返回 JWT exp （到期）时间戳，如果不存在则返回null 。
                .getExpiration()
                //测试此日期是否在指定日期之前。
                .before(new Date());
    }

    /**
     * Subject:获取 jwt 所面向的用户
     *
     * @param jwt
     * @return
     */
    public static String getSubject(String jwt) {
        return getBody(jwt).getSubject();
    }

    /**
     * Issuer:获取颁发者
     *
     * @param jwt
     * @return
     */
    public static String getIssuer(String jwt) {
        return getBody(jwt).getIssuer();
    }

    /**
     * getClaimsValue
     *
     * @param jwt
     * @return
     */
    public static String getClaimsValue(String jwt) {
        return (String) getBody(jwt).get("demo");
    }


}
